﻿using Microsoft.Extensions.DependencyInjection;
using Modules.Corp.Repositories;
using PmSoft;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Modules.Corp;

/// <summary>
/// 企业信用代码主键索引器
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class CorpCodeIndexer
{
    private static readonly ConcurrentDictionary<int, string> idToKeyDict = new();
    private static readonly ConcurrentDictionary<string, int> keyToIdDict = new();
    private static readonly SemaphoreSlim _lock = new(initialCount: 1, maxCount: 1);

    private readonly CorpInfoRepository corpInfoRepository;

    public CorpCodeIndexer(CorpInfoRepository corpInfoRepository)
    {
        this.corpInfoRepository = corpInfoRepository;
    }

    /// <summary>
    /// 根据企业ID获取企业信用代码
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string GetCorpCode(int id)
    {
        if (idToKeyDict.TryGetValue(id, out string? corpCode))
            return corpCode;

        try
        {
            _lock.Wait();

            if (idToKeyDict.TryGetValue(id, out corpCode))
                return corpCode;

            var corpInfo = corpInfoRepository.Get(id);
            if (corpInfo != null
                && !string.IsNullOrEmpty(corpInfo.Code)
                && idToKeyDict.TryAdd(id, corpInfo.Code))
            {
                return corpInfo.Code;
            }
            return string.Empty;
        }
        finally
        {
            _lock.Release();
        }
    }

    /// <summary>
    /// 根据企业信用代码获取企业ID
    /// </summary>
    /// <param name="corpCode"></param>
    /// <returns></returns>
    public int? GetId(string corpCode)
    {
        if (keyToIdDict.TryGetValue(corpCode, out int id))
            return id;
        try
        {
            _lock.Wait();

            if (keyToIdDict.TryGetValue(corpCode, out id))
                return id;

            int? corpId = corpInfoRepository.GetCorpId(corpCode);
            if (corpId.HasValue && corpId > 0 && keyToIdDict.TryAdd(corpCode, corpId.Value))
                return corpId.Value;

            return null;
        }
        finally
        {
            _lock.Release();
        }
    }

    public bool Remove(int id)
    {
        if (idToKeyDict.TryRemove(id, out string? key)
            && keyToIdDict.TryRemove(key, out _))
            return true;
        return false;
    }

}
